package com.yt.lxh.activity.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yt.lxh.activity.mapper.CouponUseMapper;
import com.yt.lxh.activity.service.CouponInfoService;
import com.yt.lxh.activity.service.CouponUseService;
import com.yt.lxh.common.exception.ServiceException;
import com.yt.lxh.common.result.ResultCodeEnum;
import com.yt.lxh.common.utils.RandomUtil;
import com.yt.lxh.enums.CouponStatus;
import com.yt.lxh.enums.CouponUseStatus;
import com.yt.lxh.model.activity.CouponInfo;
import com.yt.lxh.model.activity.CouponUse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
public class CouponUseServiceImpl extends ServiceImpl<CouponUseMapper, CouponUse> implements CouponUseService {

    @Autowired
    private CouponUseMapper couponUseMapper;

    @Autowired
    private CouponInfoService couponInfoService;

//    @Autowired
//    private RedissonClient redissonClient;

    /**
     * 领取优惠券，判断优惠券是否达到领取要求
     * @param userId 用户ID
     * @param couponId 优惠券ID
     * @return
     */
    @Override
    public void receiveCoupon(String userId, String couponId) {
        // =========== 校验数据开始 ==========
        if (StrUtil.isBlank(userId) && StrUtil.isBlank(couponId)) {
            throw new ServiceException(ResultCodeEnum.PARAM_REQUIRE);
        }
        CouponInfo couponInfo = couponInfoService.getById(couponId);
        if (couponInfo == null) {
            throw new ServiceException(ResultCodeEnum.DATA_NOT_EXIST);
        }
        if (couponInfo.getStatus() != CouponStatus.RUNNING) {
            throw new ServiceException(ResultCodeEnum.FAIL, "优惠券没有进行中");
        }
        DateTime now = DateUtil.date();
        if (now.isBefore(couponInfo.getStartTime()) || now.isAfter(couponInfo.getEndTime())) {
            throw new ServiceException(ResultCodeEnum.FAIL, "优惠券不在领取时间内或未开放");
        }
        if (couponInfo.getReceiveCount() >= couponInfo.getPublishCount()) {
            throw new ServiceException(ResultCodeEnum.FAIL, "该优惠券数量已被领完");
        }
        // =========== 校验数据结束 ==========

        // 获取锁对象
//        RLock lock = redissonClient.getLock(ActivityConst.LOCK_COUPON_RECEIVE + userId);
        try {
            // 加锁
//            boolean isLock = lock.tryLock();
//            if (!isLock) throw new ServiceException(ResultCodeEnum.FAIL, "操作太频繁了~");
            // 从aop上下文中 获取当前类的代理对象
            CouponUseService CouponUseServiceProxy = (CouponUseService) AopContext.currentProxy();
            // 调用代理对象的方法，防止事务失效
            CouponUseServiceProxy.checkAndCreateUserCoupon(userId, couponInfo);
        } finally {
            // 释放锁
//            lock.unlock();
        }
    }

    /**
     * 检查与领取 优惠券
     * @param userId 用户ID
     * @param couponInfo 优惠券信息
     */
    @Override
    @Transactional
    public void checkAndCreateUserCoupon(String userId, CouponInfo couponInfo) {
        // 判断用户是否达到该优惠券的领取上限
        Integer count = couponUseMapper.selectCount(Wrappers.<CouponUse>lambdaQuery()
                .eq(CouponUse::getCouponId, couponInfo.getId())
                .eq(CouponUse::getUserId, userId));
        if (count != null && count >= couponInfo.getPerLimit()) {
            throw new ServiceException(ResultCodeEnum.DATA_EXIST, "该优惠券已达到限领上限");
        }
        // 添加优惠券领取数量
        couponInfoService.incrReceiveCount(couponInfo);
        // 封装数据，插入一条数据，领取优惠券
        CouponUse couponUse = new CouponUse();
        couponUse.setId(RandomUtil.createLongId());
        couponUse.setCouponId(couponInfo.getId().toString());
        couponUse.setUserId(userId);
        couponUse.setUseStatus(CouponUseStatus.NOT_USED);
        couponUse.setGetTime(DateUtil.date());
        couponUse.setExpireTime(couponInfo.getExpireTime());
        couponUse.setCreateUser(userId);
        couponUse.setUpdateUser(userId);
        couponUseMapper.insert(couponUse);
    }
}
